namespace Example.Models
{
    using System.Collections.ObjectModel;
    using System.Xml.XPath;
    using SimpleWebServices;
    using SimpleWebServices.Models;
    using SimpleWebServices.Security.Cryptography;
    using SimpleWebServices.Security.Principal;
    using Xunit;

    public sealed class RegisteredUserFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<RegisteredUser>()
                .DerivesFrom<User>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            RegisteredUser actual = (
                "<user>" +
                    "<email address='john.doe@example.com' />" +
                    "<name salutation='Mr' given='John' family='Doe' />" +
                    "<roles>" +
                        "<role>Administrator</role>" +
                        "<role>Public</role>" +
                    "</roles>" +
                    "<password hash='EayiFl2Ny1C1Ri7CAAi+TVwUl/+zFCabS7zsq0Nppa4=' salt='Eajjf31MPFgt7g==' />" +
                "</user>").Deserialize<RegisteredUser>();

            Assert.NotNull(actual);

            Assert.Equal<string>("john.doe@example.com", actual.Email.Address);

            Assert.Equal<string>("Mr", actual.Name.Salutation);
            Assert.Equal<string>("John", actual.Name.Given);
            Assert.Equal<string>("Doe", actual.Name.Family);

            Assert.Equal<int>(2, actual.Roles.Count);
            Assert.Equal<string>("Administrator", actual.Roles[0]);
            Assert.Equal<string>("Public", actual.Roles[1]);

            Assert.True(actual.Password.Authenticate("password"));
        }

        [Fact]
        public void deserializeEmpty()
        {
            RegisteredUser actual = "<user />".Deserialize<RegisteredUser>();

            Assert.NotNull(actual);
            Assert.NotNull(actual.Name);
            Assert.Empty(actual.Roles);
        }

        [Fact]
        public void serialize()
        {
            RegisteredUser obj = new RegisteredUser
            {
                Email = new Email
                {
                    Address = "john.doe@example.com"
                },
                Name = new PersonalName
                {
                    Salutation = "Mr",
                    Given = "John",
                    Family = "Doe"
                },
                Roles = new Collection<string>
                {
                    "Adminstrator", "Public"
                },
                Password = SecureHashPassword.Compute("password")
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            Assert.True((bool)navigator.Evaluate("1=count(/user)"));

            Assert.True((bool)navigator.Evaluate("1=count(/user/email)"));
            Assert.True((bool)navigator.Evaluate("1=count(/user/email[@address='john.doe@example.com'])"));

            Assert.True((bool)navigator.Evaluate("1=count(/user/name)"));
            Assert.True((bool)navigator.Evaluate("1=count(/user/name[@salutation='Mr'][@given='John'][@family='Doe'])"));

            Assert.True((bool)navigator.Evaluate("2=count(/user/roles/role)"));
            Assert.True((bool)navigator.Evaluate("'Adminstrator'=/user/roles/role[1]"));
            Assert.True((bool)navigator.Evaluate("'Public'=/user/roles/role[2]"));

            Assert.True((bool)navigator.Evaluate("1=count(/user/password[@hash][@salt])"));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new RegisteredUser());
        }

        [Fact]
        public void prop_Password()
        {
            Assert.True(new PropertyExpectations(typeof(RegisteredUser).GetProperty("Password"))
                .XmlElement("password")
                .IsAutoProperty<SecureHashPassword>()
                .Result);
        }
    }
}